﻿/* 
 * Copyright (c) 2010 Letwory Interactive
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * -- Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * -- Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * Original contributor: Nathan Letwory
 */

using System;

namespace VerseSharp
{
    public delegate void BitmapTileSetCallback(BitmapTileSetCommand command);

    public interface IBitmapTile {
        BitmapLayerType Type { get; }
        void Serialize(byte[] destination, ref int pos);
        void Deserialize(byte[] source, ref int pos);
    }

    /// <summary>
    /// one-pixel tile.
    /// </summary>
    public class BitmapTileVUint1 : IBitmapTile {
        public byte[] data;

        public BitmapTileVUint1() { data = new byte[8]; }

        public BitmapLayerType Type { get { return BitmapLayerType.UInt1; } }
        public void Deserialize(byte[] source, ref int pos)
        {
            for (int i = 0; i < 8; i++)
            {
                data[i] = Utils.GetUInt8(source, ref pos);
            }
        }

        public void Serialize(byte[] destination, ref int pos)
        {
            for (int i = 0; i < 8; i++)
            {
                Utils.PutUInt8(destination, ref pos, data[i]);
            }
        }
    }

    /// <summary>
    /// 8x8 tile of byte
    /// </summary>
    public class BitmapTileVUint8 : IBitmapTile {
        public byte[] data;
        public BitmapTileVUint8() { data = new byte[64]; }
        public BitmapLayerType Type { get { return BitmapLayerType.UInt8; } }
        public void Deserialize(byte[] source, ref int pos)
        {
            for (int i = 0; i < 64; i++)
            {
                data[i] = Utils.GetUInt8(source, ref pos);
            }
        }

        public void Serialize(byte[] destination, ref int pos)
        {
            for (int i = 0; i < 64; i++)
            {
                Utils.PutUInt8(destination, ref pos, data[i]);
            }
        }
    }

    /// <summary>
    /// 8x8 tile of ushort
    /// </summary>
    public class BitmapTileVUint16 : IBitmapTile {
        public ushort[] data;
        public BitmapTileVUint16() { data = new ushort[64]; }
        public BitmapLayerType Type { get { return BitmapLayerType.UInt16; } }
        public void Deserialize(byte[] source, ref int pos)
        {
            for (int i = 0; i < 64; i++)
            {
                data[i] = Utils.GetUInt16(source, ref pos);
            }
        }

        public void Serialize(byte[] destination, ref int pos)
        {
            for (int i = 0; i < 64; i++)
            {
                Utils.PutUInt16(destination, ref pos, data[i]);
            }
        }
    }

    /// <summary>
    /// 8x8 tile of float
    /// </summary>
    public class BitmapTileVReal32 : IBitmapTile
    {
        public float[] data;
        public BitmapTileVReal32() { data = new float[64]; }
        public BitmapLayerType Type { get { return BitmapLayerType.Real32; } }
        public void Deserialize(byte[] source, ref int pos)
        {
            for (int i = 0; i < 64; i++)
            {
                data[i] = Utils.GetReal32(source, ref pos);
            }
        }

        public void Serialize(byte[] destination, ref int pos)
        {
            for (int i = 0; i < 64; i++)
            {
                Utils.PutReal32(destination, ref pos, data[i]);
            }
        }
    }

    /// <summary>
    /// 8x8 tile of double
    /// </summary>
    public class BitmapTileVReal64 : IBitmapTile
    {
        public double[] data;
        public BitmapTileVReal64() { data = new double[64]; }
        public BitmapLayerType Type { get { return BitmapLayerType.Real64; } }
        public void Deserialize(byte[] source, ref int pos)
        {
            for (int i = 0; i < 64; i++)
            {
                data[i] = Utils.GetReal64(source, ref pos);
            }
        }

        public void Serialize(byte[] destination, ref int pos)
        {
            for (int i = 0; i < 64; i++)
            {
                Utils.PutReal64(destination, ref pos, data[i]);
            }
        }
    }

    /// <summary>
    /// Command to set a tile with tile data.
    /// </summary>
    public class BitmapTileSetCommand: IVerseCommand
    {
        /// <summary>
        /// Protocol ID of the command.
        /// </summary>
        public CommandID ID { get { return CommandID.BitmapTileSet; } }
        /// <summary>
        /// ID of the node being accessed.
        /// </summary>
        public uint NodeID;
        /// <summary>
        /// ID of the layer being accessed.
        /// </summary>
        public ushort LayerID;
        /// <summary>
        /// x-coordinate (in the tile grid) of this tile of pixels.
        /// </summary>
        public ushort TileX;
        /// <summary>
        /// y-coordinate (in the tile grid) of this tile of pixels.
        /// </summary>
        public ushort TileY;
        /// <summary>
        /// z-coordinate (in the tile grid) of this tile of pixels.
        /// </summary>
        public ushort Z;
        /// <summary>
        /// Type of data to set.
        /// </summary>
        public BitmapLayerType Type;
        /// <summary>
        /// The actual tile.
        /// </summary>
        public IBitmapTile Data;

        public void Deserialize(byte[] source, ref int pos)
        {
            NodeID = Utils.GetUInt32(source, ref pos);
            LayerID = Utils.GetUInt16(source, ref pos);
            TileX = Utils.GetUInt16(source, ref pos);
            TileX = Utils.GetUInt16(source, ref pos);
            Z = Utils.GetUInt16(source, ref pos);
            Type = (BitmapLayerType)Utils.GetUInt8(source, ref pos);
            switch (Type)
            {
                case BitmapLayerType.UInt1:
                    Data = new BitmapTileVUint1();
                    Data.Deserialize(source, ref pos);
                    break;
                case BitmapLayerType.UInt8:
                    Data = new BitmapTileVUint8();
                    Data.Deserialize(source, ref pos);
                    break;
                case BitmapLayerType.UInt16:
                    Data = new BitmapTileVUint16();
                    Data.Deserialize(source, ref pos);
                    break;
                case BitmapLayerType.Real32:
                    Data = new BitmapTileVReal32();
                    Data.Deserialize(source, ref pos);
                    break;
                case BitmapLayerType.Real64:
                    Data = new BitmapTileVReal64();
                    Data.Deserialize(source, ref pos);
                    break;
            }
        }

        public void Serialize(byte[] destination, ref int pos)
        {
            Utils.PutUInt32(destination, ref pos, NodeID);
            Utils.PutUInt16(destination, ref pos, LayerID);
            Utils.PutUInt16(destination, ref pos, TileX);
            Utils.PutUInt16(destination, ref pos, TileY);
            Utils.PutUInt16(destination, ref pos, Z);
            Utils.PutUInt8(destination, ref pos, (byte)Type);
            Data.Serialize(destination, ref pos);
        }
    }
}
